package com.jinmdz.fmis.api.api.service;

import com.jinmdz.fmis.api.api.model.coldstorage.ColdStorageAllData;
import com.jinmdz.fmis.api.api.model.coldstorage.ColdStorageAllDeadData;
import com.jinmdz.fmis.api.api.model.coldstorage.ColdStorageAllLoadData;
import com.jinmdz.fmis.api.api.model.coldstorage.ColdStorageData;
import com.jinmdz.fmis.api.api.model.common.BusinessCharges;
import com.jinmdz.fmis.api.api.model.common.DataCodeData;
import com.jinmdz.fmis.api.api.model.common.IdData;
import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.constant.MessageConst;
import com.jinmdz.fmis.api.model.config.dictionary.BusinessLogCode;
import com.jinmdz.fmis.api.model.config.dictionary.ColdStorageStatusCode;
import com.jinmdz.fmis.api.model.config.dictionary.OperationLogCode;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.api.wrapper.ChargeWrapper;
import com.jinmdz.fmis.api.wrapper.DictionaryWrapper;
import com.jinmdz.fmis.api.wrapper.OperationWrapper;
import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.BeanUtil;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.common.util.DateUtil;
import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.constant.EBusinessType;
import com.jinmdz.fmis.core.constant.EDictCode;
import com.jinmdz.fmis.core.constant.PurposeConst;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.core.util.JacksonUtil;
import com.jinmdz.fmis.dao.dao.*;
import com.jinmdz.fmis.dao.model.charge.ChargeItem;
import com.jinmdz.fmis.dao.model.coldstorage.ColdStorageEquipmentViewItem;
import com.jinmdz.fmis.dao.model.coldstorage.ColdStorageItem;
import com.jinmdz.fmis.dao.model.coldstorage.ColdStorageViewItem;
import com.jinmdz.fmis.dao.model.funeral.FuneralBusinessViewItem;
import com.jinmdz.fmis.dao.model.funeral.FuneralDeadItem;
import com.jinmdz.fmis.dao.model.service.ServiceItem;
import com.jinmdz.fmis.mapper.entity.ChargeItemEntity;
import com.jinmdz.fmis.mapper.entity.ColdStorageEntity;
import com.jinmdz.fmis.mapper.entity.FuneralBusinessLogEntity;
import com.jinmdz.fmis.mapper.mapper.ColdStorageMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

/**
 * ColdStorageService类
 *
 * @author LiCongLu
 * @date 2020-01-20 13:11
 */
@Service("coldStorageService")
public class ColdStorageService extends BaseService {

    @Resource
    private FuneralBusinessDao funeralBusinessDao;

    @Resource
    private ColdStorageMapper coldStorageMapper;

    @Resource
    private ColdStorageStatusCode coldStorageStatusCode;

    @Resource
    private ServiceItemDao serviceItemDao;

    @Resource
    private ChargeItemDao chargeItemDao;

    @Resource
    private ColdStorageDao coldStorageDao;

    @Resource
    private ColdStorageEquipmentDao coldStorageEquipmentDao;

    @Resource
    private ChargeWrapper chargeWrapper;

    @Resource
    private DictionaryService dictionaryService;

    @Resource
    private OperationLogCode operationLogCode;

    @Resource
    private OperationWrapper operationWrapper;

    @Resource
    private DictionaryWrapper dictionaryWrapper;

    @Resource
    private BusinessLogCode businessLogCode;

    @Resource
    private FuneralDeadDao funeralDeadDao;

    @Resource
    private DataDictionaryDao dataDictionaryDao;

    /**
     * 根据cold_storage表中id加载冷藏任务信息
     *
     * @param data 冷藏主键
     * @return
     * @author LiCongLu
     * @date 2020-01-20 13:14
     */
    public BaseResult<ColdStorageData> loadColdStorageWithId(IdData data) {
        Integer loadId = data.getId();

        // 查询业务信息
        ColdStorageViewItem loadItem = coldStorageDao.getColdStorageViewById(loadId);
        if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
            return failure("主键错误，不存在此业务信息");
        }

        ColdStorageData loadData = loadColdStorageData(loadItem);

        // 返回响应结果
        return successData(loadData);
    }

    /**
     * 获取业务费用等数据
     *
     * @param loadItem 已加载数据
     * @return
     * @author LiCongLu
     * @date 2020-02-16 11:23
     */
    private ColdStorageData loadColdStorageData(ColdStorageItem loadItem) {
        // 创建响应实体，并赋值
        ColdStorageData loadData = BeanUtil.copy2Bean(loadItem, new ColdStorageData());

        loadData.setCharges(new BusinessCharges());

        ChargeItem businessCharge = chargeItemDao.getChargeItemById(loadItem.getChargeId());
        loadData.getCharges().setBusinessCharge(businessCharge);

        // 业务费用主键
        Integer businessChargeId = businessCharge != null ? businessCharge.getId() : 0;

        ArrayList<ChargeItem> goodsServices = chargeItemDao.listChargeItemByRandomCode(loadItem.getBusinessCode(), loadItem.getRandomCode(), businessChargeId);
        loadData.getCharges().setGoodsServices(goodsServices);
        // 设置文本值
        dictionaryWrapper.resetDataText(loadData);
        return loadData;
    }

    /**
     * 保存冷藏信息到cold_storage表中
     *
     * @param userItem 当前帐号
     * @param data     冷藏请求数据
     * @return
     * @author LiCongLu
     * @date 2020-01-20 13:15
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult<ColdStorageData> saveColdStorage(UserItem userItem, ColdStorageData data) throws ActionException {
        String businessCode = data.getBusinessCode();
        // 通过业务编码获取殡葬信息
        FuneralBusinessViewItem funeralItem = funeralBusinessDao.getFuneralBusinessViewByBusinessCode(businessCode);
        if (DataUtil.isNull(funeralItem) || DataUtil.isNull(funeralItem.getId(), funeralItem.getVersion())) {
            throw exception(MessageConst.NO_FUNERAL_CODE);
        }

        Integer id = data.getId();
        // 主键不为空
        if (DataUtil.valid(id)) {
            updateColdStorage(userItem, funeralItem, data);
        } else {
            id = insertColdStorage(userItem, funeralItem, data);
        }
        return loadColdStorageWithId(new IdData(id));
    }

    /**
     * 插入冷藏信息
     *
     * @param userItem    当前帐号
     * @param funeralItem 殡葬业务
     * @param data        新增冷藏信息
     * @return
     * @author LiCongLu
     * @date 2020-02-15 10:58
     */
    private Integer insertColdStorage(UserItem userItem, FuneralBusinessViewItem funeralItem, ColdStorageData data) throws ActionException {
        // 创建冷藏实体
        ColdStorageEntity entity = getEntity(userItem, ColdStorageEntity.class);

        // 判断流程状态
        if (!DataUtil.inIntegers(data.getProcessStateCode()
                , coldStorageStatusCode.getYiYuDing()
                , coldStorageStatusCode.getWeiRuCang()
                , coldStorageStatusCode.getYiRuCang()
                , coldStorageStatusCode.getYiChuCang()
                , coldStorageStatusCode.getYiLinShiChuCang())) {
            throw exception("冷藏状态值错误");
        }

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 创建业务随机码
        entity.setRandomCode(DataUtil.getUUID());

        // 依照状态等设置默认值
        saveColdStorageValue(data, entity);

        // 验证冷藏设备占用状态
        checkColdStorageEquipment(data);

        // 判断设备及状态
        insertColdStorageEquipmentState(userItem, entity);

        // 插入业务费用
        ChargeItem businessCharge = data.getCharges().getBusinessCharge();
        businessCharge.setBusinessCode(entity.getBusinessCode())
                .setRandomCode(entity.getRandomCode())
                .setItemNumber(data.getRuleNumber())
                .setItemUnit(data.getRuleUnit());

        // 验证是否不可结算
        checkBusinessChargeUnsettled(entity, businessCharge);

        String dictCode = EDictCode.EQUIPMENT_TYPE.getCode();
        String purpose = PurposeConst.YI_TI_LENG_CANG;
        int chargeId = chargeWrapper.insertBusinessCharge(userItem, businessCharge, dictCode, entity.getEquipmentTypeCode(), purpose, data.getRuleRemark());
        entity.setChargeId(chargeId);

        // 插入物品服务
        ArrayList<ChargeItemEntity> chargeEntities = chargeWrapper.insertGoodsServices(userItem, entity.getBusinessCode(), entity.getRandomCode(), EBusinessType.USE_IN_COLD_STORAGE.getType(), data.getCharges().getGoodsServices());

        // 新增冷藏信息
        coldStorageMapper.insertColdStorage(entity);
        // 判断保存冷藏信息结果
        if (DataUtil.invalid(entity.getId())) {
            throw exception("保存冷藏信息失败");
        }

        // 添加业务及操作日志
        Integer logTypeCode = operationLogCode.getColdStorageInsert();
        Integer chargeLogTypeCode = operationLogCode.getChargeInsert();
        saveColdStorageLog(userItem, funeralItem, data, entity, logTypeCode, chargeLogTypeCode, businessCharge, chargeEntities, null);

        return entity.getId();
    }

    /**
     * 验证是否不可结算
     *
     * @param entity         数据实体
     * @param businessCharge 业务费用
     * @return
     * @author LiCongLu
     * @date 2020-05-15 10:54
     */
    private void checkBusinessChargeUnsettled(ColdStorageEntity entity, ChargeItem businessCharge) {
        boolean unsettled = false;
        // 判断条件：1.预约出藏时间为空
        if (DataUtil.isNull(entity.getAppointmentOutTime())) {
            unsettled = true;
        }

        // 设置不可结算状态
        businessCharge.setAsUnsettled(unsettled ? 1 : 0);
    }

    /**
     * 添加冷藏日志记录
     *
     * @param userItem          当前帐号
     * @param funeralItem       当前业务
     * @param data              请求数据
     * @param entity            数据实体
     * @param logTypeCode       日志记录类型
     * @param chargeLogTypeCode 费用日志类型
     * @param businessCharge    业务费用
     * @param chargeEntities    费用记录
     * @param deleteEntities    删除费用记录
     * @return
     * @author LiCongLu
     * @date 2020-02-25 14:33
     */
    private void saveColdStorageLog(UserItem userItem, FuneralBusinessViewItem funeralItem
            , ColdStorageData data, ColdStorageEntity entity
            , Integer logTypeCode, Integer chargeLogTypeCode
            , ChargeItem businessCharge, ArrayList<ChargeItemEntity> chargeEntities, ArrayList<ChargeItemEntity> deleteEntities) throws ActionException {

        // 添加业务日志及操作日志
        String businessCode = funeralItem.getBusinessCode();
        Integer typeCode = getLogTypeForStateCode(entity.getProcessStateCode());
        FuneralBusinessLogEntity businessLogEntity = operationWrapper.businessLog(userItem, businessCode, typeCode);

        // 获取新设备信息
        ColdStorageEquipmentViewItem equipmentItem = coldStorageEquipmentDao.getColdStorageEquipmentViewById(entity.getEquipmentId());
        String equipmentCode = DataUtil.isNull(equipmentItem) ? "" : equipmentItem.getEquipmentCode();

        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("保存冷藏信息，业务编码[{0}]，逝者姓名[{1}]，冷藏设备类型[{2}][{3}]，冷藏设备编号[{4}]，预约入藏时间[{5}]，预约出藏时间[{6}]，冷藏状态[{7}]" +
                        " ，冷藏费用[{8}]，操作人员[{9}]"
                , businessCode, funeralItem.getDeadName()
                , String.valueOf(entity.getEquipmentTypeCode())
                , dictionaryWrapper.getDataText(EDictCode.EQUIPMENT_TYPE, entity.getEquipmentTypeCode())
                , equipmentCode
                , DateUtil.formatPattern16(entity.getAppointmentInTime()), DateUtil.formatPattern16(entity.getAppointmentOutTime())
                , dictionaryWrapper.getDataText(EDictCode.REFRIGERATED_STATE, entity.getProcessStateCode())
                , DataUtil.getPlainString(businessCharge.getItemCharge()), userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, businessLogEntity, logTypeCode, builder.toString(),
                JacksonUtil.obj2Json(data), null, JacksonUtil.obj2Json(entity));

        // 累计费用总金额
        if (DataUtil.valid(chargeEntities)) {
            BigDecimal sumCharge = new BigDecimal(0);
            for (ChargeItemEntity chargeEntity : chargeEntities) {
                sumCharge = sumCharge.add(chargeEntity.getItemCharge());
            }
            // 添加物品服务费用日志
            builder.clear();
            builder.format("保存冷藏信息更新物品服务，业务编码[{0}]，逝者姓名[{1}]，冷藏费用[{2}]，物品服务总金额[{3}]"
                    , businessCode, funeralItem.getDeadName()
                    , DataUtil.getPlainString(businessCharge.getItemCharge()), DataUtil.getPlainString(sumCharge));
            operationWrapper.operationLog(userItem, businessLogEntity, chargeLogTypeCode
                    , builder.toString(), JacksonUtil.obj2Json(data.getCharges().getGoodsServices()), null, JacksonUtil.obj2Json(chargeEntities));
        }

        // 删除费用总金额
        if (DataUtil.valid(deleteEntities)) {
            BigDecimal sumCharge = new BigDecimal(0);
            for (ChargeItemEntity chargeEntity : deleteEntities) {
                sumCharge = sumCharge.add(chargeEntity.getItemCharge());
            }
            // 删除物品服务费用日志
            builder.clear();
            builder.format("保存冷藏信息删除物品服务，业务编码[{0}]，逝者姓名[{1}]，删除物品服务总金额[{2}]"
                    , businessCode, funeralItem.getDeadName(), DataUtil.getPlainString(sumCharge));
            operationWrapper.operationLog(userItem, businessLogEntity, operationLogCode.getChargeDelete()
                    , builder.toString(), null, JacksonUtil.obj2Json(deleteEntities), null);
        }
    }

    /**
     * 验证流程状态值
     *
     * @param stateCode 流程状态值
     * @return
     * @author LiCongLu
     * @date 2020-02-24 17:20
     */
    private Integer getLogTypeForStateCode(int stateCode) throws ActionException {
        // 处理状态
        if (DataUtil.equals(stateCode, coldStorageStatusCode.getYiYuDing())) {
            return businessLogCode.getColdStorageYiYuDing();
        } else if (DataUtil.equals(stateCode, coldStorageStatusCode.getWeiRuCang())) {
            return businessLogCode.getColdStorageWeiRuCang();
        } else if (DataUtil.equals(stateCode, coldStorageStatusCode.getYiRuCang())) {
            return businessLogCode.getColdStorageYiRuCang();
        } else if (DataUtil.equals(stateCode, coldStorageStatusCode.getYiChuCang())) {
            return businessLogCode.getColdStorageYiChuCang();
        } else if (DataUtil.equals(stateCode, coldStorageStatusCode.getYiLinShiChuCang())) {
            return businessLogCode.getColdStorageYiLinShiChuCang();
        } else {
            throw exception("流转状态值错误");
        }
    }

    /**
     * 依据状态等设置默认值
     *
     * @param data   请求数据
     * @param entity 数据实体
     * @return
     * @author LiCongLu
     * @date 2020-02-17 9:43
     */
    private void saveColdStorageValue(ColdStorageData data, ColdStorageEntity entity) throws ActionException {
        Date nowDate = nowDate();
        // 处理状态
        int stateCode = data.getProcessStateCode();
        if (DataUtil.equals(stateCode, coldStorageStatusCode.getYiYuDing())) {

        } else if (DataUtil.equals(stateCode, coldStorageStatusCode.getWeiRuCang())) {
        } else if (DataUtil.equals(stateCode, coldStorageStatusCode.getYiRuCang())) {
            if (DataUtil.isNull(entity.getRealityInTime())) {
                // 已入藏状态，但未填写实际入藏时间的，设置实际入藏时间
                entity.setRealityInTime(nowDate);
            }
        } else if (DataUtil.equals(stateCode, coldStorageStatusCode.getYiChuCang())) {
            if (DataUtil.isNull(entity.getRealityOutTime())) {
                // 已出藏状态，但未填写实际出藏时间的，设置实际出藏时间
                entity.setRealityOutTime(nowDate);
            }
        } else if (DataUtil.equals(stateCode, coldStorageStatusCode.getYiLinShiChuCang())) {

        } else {
            throw exception("流转状态值错误");
        }

        // 判断预约时间
        if (!DataUtil.equals(stateCode, coldStorageStatusCode.getYiYuDing())) {
            // 预约设备主键不能为空
            if (DataUtil.invalid(data.getEquipmentId())) {
                throw exception("设备主键不能为空！");
            }

            // 预约时间不能为空
            if (DataUtil.isNull(data.getAppointmentInTime())) {
                throw exception("预约入藏时间不能为空！");
            }
        }

        // 判断时间节点
        if (DataUtil.noNullOrEmpty(data.getAppointmentInTime(), data.getAppointmentOutTime())) {
            if (data.getAppointmentInTime().after(data.getAppointmentOutTime())) {
                throw exception("预约入藏时间晚于预约出藏时间");
            }
        }
    }

    /**
     * 新增验证设备
     *
     * @param userItem 当前帐号
     * @param entity   保存实体
     * @return
     * @author LiCongLu
     * @date 2020-02-17 11:18
     */
    private void insertColdStorageEquipmentState(UserItem userItem, ColdStorageEntity entity) throws ActionException {
        // 如果是已出藏状态
        if (DataUtil.equals(entity.getProcessStateCode(), coldStorageStatusCode.getYiChuCang())) {
            Date nowDate = nowDate();
            // 已出藏状态，设置出藏时间
            entity.setRealityInTime(nowDate)
                    .setRealityOutTime(nowDate);
        }

        // 如果是已入藏状态
        if (DataUtil.equals(entity.getProcessStateCode(), coldStorageStatusCode.getYiRuCang())) {
            // 已入藏状态，设置实际入藏时间
            entity.setRealityInTime(nowDate());
        }
    }

    /**
     * 验证冷藏设备状态
     *
     * @param data 请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-06 14:38
     */
    private void checkColdStorageEquipment(ColdStorageData data) throws ActionException {
        // 验证冷藏设备
        if (DataUtil.valid(data.getEquipmentId())) {
            // 获取新设备信息
            ColdStorageEquipmentViewItem dataItem = coldStorageEquipmentDao.getColdStorageEquipmentViewById(data.getEquipmentId());
            if (DataUtil.isNull(dataItem) || DataUtil.isNull(dataItem.getId(), dataItem.getVersion())) {
                throw exception("冷藏设备主键错误，不存在此设备信息");
            }

            // 判断设备类型
            if (!DataUtil.equals(dataItem.getEquipmentTypeCode(), data.getEquipmentTypeCode())) {
                throw exception("冷藏设备类型与设备所属类型不一致");
            }

            // 判断是否有效使用
            if (DataUtil.valid(dataItem.getDisableState())) {
                throw exception("冷藏设备是无效禁用状态");
            }

            // 设备占用情况
            Integer businessId = coldStorageDao.getBusinessIdForEquipmentId(data.getEquipmentId()
                    , data.getId(), coldStorageStatusCode.getYiChuCang());
            if (DataUtil.valid(businessId)) {
                throw exception("冷藏设备是占用状态，不可使用");
            }
        }
    }

    /**
     * 更新冷藏信息
     *
     * @param userItem    当前帐号
     * @param funeralItem 殡葬业务
     * @param data        更新冷藏信息
     * @return
     * @author LiCongLu
     * @date 2020-02-15 10:59
     */
    private void updateColdStorage(UserItem userItem, FuneralBusinessViewItem funeralItem, ColdStorageData data) throws ActionException {
        // 验证主键和数据版本是否存在
        if (DataUtil.isNull(data.getId(), data.getVersion())) {
            throw exception("请求冷藏信息主键与版本号不能为空");
        }

        // 判断冷藏费用
        ChargeItem businessCharge = data.getCharges().getBusinessCharge();
        if (DataUtil.invalid(businessCharge.getId())) {
            throw exception("请求冷藏费用主键不能为空");
        }

        // 通过主键获取冷藏信息
        ColdStorageEntity entity = coldStorageMapper.getColdStorageById(data.getId());
        if (DataUtil.isNull(entity) || DataUtil.isNull(entity.getId(), entity.getVersion())) {
            throw exception("冷藏主键错误，不存在此冷藏信息");
        }

        // 验证业务编码
        if (!data.getBusinessCode().equals(entity.getBusinessCode())) {
            throw exception(MessageConst.BUSINESS_CODE_ERROR);
        }

        // 验证冷藏信息版本
        if (!DataUtil.equals(data.getVersion(), entity.getVersion())) {
            throw exception(versionError("冷藏信息"));
        }

        // 判断流程状态
        if (!DataUtil.inIntegers(data.getProcessStateCode()
                , coldStorageStatusCode.getYiYuDing()
                , coldStorageStatusCode.getWeiRuCang()
                , coldStorageStatusCode.getYiRuCang()
                , coldStorageStatusCode.getYiChuCang()
                , coldStorageStatusCode.getYiLinShiChuCang())) {
            throw exception("冷藏状态值错误");
        }

        // 判断流程状态
        if (DataUtil.equals(coldStorageStatusCode.getYiLinShiChuCang(), entity.getProcessStateCode())) {
            if (!DataUtil.inIntegers(data.getProcessStateCode()
                    , coldStorageStatusCode.getYiRuCang()
                    , coldStorageStatusCode.getYiLinShiChuCang())) {
                throw exception("已临时出藏的只能选择已入藏和已临时出藏");
            }
        } else {
            if (data.getProcessStateCode().intValue() < entity.getProcessStateCode().intValue()) {
                throw exception("冷藏状态值不允许回退选择");
            }
        }

        // 验证业务与业务费用是否匹配
        if (businessCharge.getId().intValue() != entity.getChargeId().intValue()
                || !businessCharge.getBusinessCode().equals(entity.getBusinessCode())) {
            throw exception("业务费用与业务不匹配");
        }

        // 依照状态等设置默认值
        saveColdStorageValue(data, entity);

        // 验证冷藏设备占用状态
        checkColdStorageEquipment(data);

        // 业务费用
        ChargeItem chargeItem = chargeItemDao.getChargeItemById(entity.getChargeId());

        // 判断设备及状态
        updateColdStorageEquipmentState(userItem, DataUtil.valid(chargeItem.getAsSettled()), data, entity);

        // 更新业务费用
        businessCharge.setBusinessCode(entity.getBusinessCode())
                .setRandomCode(entity.getRandomCode())
                .setItemNumber(data.getRuleNumber())
                .setItemUnit(data.getRuleUnit())
                .setId(entity.getChargeId());

        // 验证是否不可结算
        checkBusinessChargeUnsettled(entity, businessCharge);

        String dictCode = EDictCode.EQUIPMENT_TYPE.getCode();
        String purpose = PurposeConst.YI_TI_LENG_CANG;
        chargeWrapper.updateBusinessCharge(userItem, businessCharge, dictCode, data.getEquipmentTypeCode(), purpose, data.getRuleRemark());

        // 业务费用主键
        Integer businessChargeId = businessCharge != null ? businessCharge.getId() : 0;
        // 更新物品服务
        ArrayList<ChargeItemEntity> chargeEntities = chargeWrapper.updateGoodsServices(userItem, entity.getBusinessCode(), entity.getRandomCode(), EBusinessType.USE_IN_COLD_STORAGE.getType(), businessChargeId, data.getCharges().getGoodsServices());

        // 删除物品服务
        ArrayList<ChargeItemEntity> deleteEntities = chargeWrapper.deleteGoodsServices(userItem, entity.getBusinessCode(), entity.getRandomCode(), EBusinessType.USE_IN_COLD_STORAGE.getType(), data.getCharges().getDeleteIds());

        // 设置修改帐号
        entity.setModifiedUserId(userItem.getId());
        // 更新冷藏信息
        coldStorageMapper.updateColdStorage(entity);

        // 添加业务及操作日志
        Integer logTypeCode = operationLogCode.getColdStorageUpdate();
        Integer chargeLogTypeCode = operationLogCode.getChargeUpdate();
        saveColdStorageLog(userItem, funeralItem, data, entity, logTypeCode, chargeLogTypeCode, businessCharge, chargeEntities, deleteEntities);
    }

    /**
     * 更新验证设备
     *
     * @param userItem 当期账号
     * @param settled  是否结算
     * @param data     请求数据
     * @param entity   保存实体
     * @return
     * @author LiCongLu
     * @date 2020-02-17 11:18
     */
    private void updateColdStorageEquipmentState(UserItem userItem, boolean settled, ColdStorageData data, ColdStorageEntity entity) throws ActionException {
        // 新设备主键为空时
        if (DataUtil.invalid(data.getEquipmentId())) {
            // 如果原状态是已预订状态，取消占用状态
            if (!DataUtil.equals(entity.getProcessStateCode(), coldStorageStatusCode.getYiYuDing())) {
                throw exception("非已预订状态，设备主键不能空");
            }
        }

        // 如果新状态是入藏状态
        if (DataUtil.equals(data.getProcessStateCode(), coldStorageStatusCode.getYiRuCang())) {
            if (DataUtil.isNull(entity.getRealityInTime())) {
                // 已入藏状态，设置实际入藏时间
                entity.setRealityInTime(nowDate());
            }
        }

        // 如果新状态是出藏状态
        if (DataUtil.equals(data.getProcessStateCode(), coldStorageStatusCode.getYiChuCang())) {
            if (DataUtil.isNull(entity.getRealityOutTime())) {
                // 已出藏状态，设置实际出藏时间
                entity.setRealityOutTime(nowDate());
                if (!settled) {
                    entity.setAppointmentOutTime(entity.getRealityOutTime());
                }
            }
        }

        // 依据业务费用更新变化，即是否结算了，来处理数据覆盖情况
        if (settled) {
            // 已结算，覆盖部分数据
            // 已结算的不能修改设备类型
            if (!DataUtil.equals(data.getEquipmentTypeCode(), entity.getEquipmentTypeCode())) {
                throw exception("已结算不能修改冷藏设备类型");
            }
            // 已结算的只更新流程状态
            entity.setProcessStateCode(data.getProcessStateCode());
            return;
        }

        // 如果原状态是已入藏、临时出藏等状态，预约入藏时间不修改
        if (DataUtil.inIntegers(entity.getProcessStateCode()
                , coldStorageStatusCode.getYiRuCang()
                , coldStorageStatusCode.getYiLinShiChuCang())) {
            data.setAppointmentInTime(entity.getAppointmentInTime());
        }

        // 如果原状态是已出藏、等状态，预约入藏时间和预约出藏时间不修改
        if (DataUtil.inIntegers(entity.getProcessStateCode()
                , coldStorageStatusCode.getYiChuCang())) {
            data.setAppointmentInTime(entity.getAppointmentInTime())
                    .setAppointmentOutTime(entity.getAppointmentOutTime());
        }

        // 未结算，覆盖数据
        BeanUtil.copy2Bean(data, entity);
    }

    /**
     * 从cold_storage表中删除指定id的冷藏任务信息记录
     *
     * @param userItem 当前帐号
     * @param data     主键和版本号
     * @return
     * @author LiCongLu
     * @date 2020-01-20 13:17
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult deleteColdStorageWithId(UserItem userItem, IdVersionData data) throws ActionException {
        // 通过主键获取冷藏信息
        ColdStorageViewItem loadItem = coldStorageDao.getColdStorageViewById(data.getId());
        if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
            return failure("主键错误，不存在此冷藏业务");
        }

        // 验证冷藏信息版本
        if (!DataUtil.equals(loadItem.getVersion(), data.getVersion())) {
            return failure(versionError("冷藏信息"));
        }

        // 验证状态，已入藏、已出藏、已临时出藏等状态不能删除
        if (DataUtil.inIntegers(loadItem.getProcessStateCode()
                , coldStorageStatusCode.getYiRuCang()
                , coldStorageStatusCode.getYiChuCang()
                , coldStorageStatusCode.getYiLinShiChuCang())) {
            return failure("已入藏、已出藏、已临时出藏等状态不能删除");
        }

        // 记录费用主键
        ArrayList<Integer> chargeIds = new ArrayList<>();
        // 判断业务费用是否存在
        ChargeItem businessCharge = chargeItemDao.getChargeItemById(loadItem.getChargeId());
        if (DataUtil.noNullOrEmpty(businessCharge)) {
            // 判断是否结算
            if (DataUtil.valid(businessCharge.getAsSettled())) {
                return failure("冷藏业务费用已经结算，无法进行删除");
            }
            chargeIds.add(businessCharge.getId());
        }

        // 业务费用主键
        Integer businessChargeId = businessCharge != null ? businessCharge.getId() : 0;

        // 判断是否已经存在结算
        ArrayList<ChargeItem> goodsServices = chargeItemDao.listChargeItemByRandomCode(loadItem.getBusinessCode(), loadItem.getRandomCode(), businessChargeId);
        if (DataUtil.valid(goodsServices)) {
            for (ChargeItem chargeItem : goodsServices) {
                if (DataUtil.valid(chargeItem.getAsSettled())) {
                    return failure("冷藏物品服务已经结算，无法进行删除");
                }
                chargeIds.add(chargeItem.getId());
            }
        }

        // 删除费用
        if (DataUtil.valid(chargeIds)) {
            chargeItemDao.deletedForChargeItem(loadItem.getBusinessCode(), chargeIds, userItem.getId());
        }

        // 删除业务任务
        coldStorageMapper.deletedForColdStorage(loadItem.getId(), userItem.getId(), loadItem.getVersion());

        // 删除日志信息
        deleteColdStorageLog(userItem, loadItem, businessCharge, goodsServices);

        return success("删除完成");
    }

    /**
     * 删除接运日志
     *
     * @param userItem       当前账号
     * @param loadItem       接运任务
     * @param businessCharge 业务费用
     * @param goodsServices  物品服务
     * @return
     * @author LiCongLu
     * @date 2020-02-25 15:57
     */
    private void deleteColdStorageLog(UserItem userItem, ColdStorageItem loadItem, ChargeItem businessCharge, ArrayList<ChargeItem> goodsServices) throws ActionException {
        // 添加业务日志及操作日志
        String businessCode = loadItem.getBusinessCode();
        Integer typeCode = businessLogCode.getColdStorageDelete();
        FuneralBusinessLogEntity businessLogEntity = operationWrapper.businessLog(userItem, businessCode, typeCode);
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("删除冷藏信息，业务编码[{0}]，操作人员[{1}]", businessCode, userItem.getFullName());
        // 添加日志
        Integer logTypeCode = operationLogCode.getColdStorageDelete();
        operationWrapper.operationLog(userItem, businessLogEntity, logTypeCode, builder.toString(), null, JacksonUtil.obj2Json(loadItem), null);

        // 累计费用总金额
        if (DataUtil.valid(goodsServices)) {
            Integer chargeLogTypeCode = operationLogCode.getChargeDelete();
            BigDecimal sumCharge = new BigDecimal(0);
            for (ChargeItem chargeItem : goodsServices) {
                sumCharge = sumCharge.add(chargeItem.getItemCharge());
            }
            // 记录业务费用
            goodsServices.add(businessCharge);
            // 添加物品服务费用日志
            builder.clear();
            builder.format("删除冷藏信息物品服务，业务编码[{0}]，冷藏费用[{1}]，物品服务总金额[{2}]", businessCode
                    , DataUtil.getPlainString(businessCharge.getItemCharge()), DataUtil.getPlainString(sumCharge));
            operationWrapper.operationLog(userItem, businessLogEntity, chargeLogTypeCode
                    , builder.toString(), null, JacksonUtil.obj2Json(goodsServices), null);
        }
    }

    /**
     * 根据冷藏柜类型加载冷藏格位信息
     *
     * @param data 格位类型字典
     * @return
     * @author LiCongLu
     * @date 2020-02-16 12:08
     */
    public BaseResult<ArrayList<ColdStorageEquipmentViewItem>> loadColdStorageEquipmentWithType(DataCodeData data) {
        ArrayList<ColdStorageEquipmentViewItem> loadItems = coldStorageEquipmentDao.listColdStorageEquipmentViewByDictCode(EDictCode.EQUIPMENT_TYPE.getCode(), data.getTypeCode(), coldStorageStatusCode.getYiChuCang());

        // 设置字典文本
        dictionaryWrapper.resetDataText(loadItems);

        // 返回响应结果
        return successList(loadItems);
    }

    /**
     * 冷藏服务洽谈，界面权限验证及基础数据加载
     *
     * @param data 加载全部数据
     * @return
     * @author LiCongLu
     * @date 2020-02-16 11:31
     */
    public BaseResult<ColdStorageAllLoadData> loadColdStorageAll(ColdStorageAllData data) {
        String businessCode = data.getBusinessCode();
        // 通过业务编码获取殡葬信息
        FuneralBusinessViewItem funeralItem = funeralBusinessDao.getFuneralBusinessViewByBusinessCode(businessCode);
        if (DataUtil.isNull(funeralItem) || DataUtil.isNull(funeralItem.getId(), funeralItem.getVersion())) {
            return failure(MessageConst.NO_FUNERAL_CODE);
        }

        ColdStorageAllLoadData allLoadData = new ColdStorageAllLoadData();

        // 加载业务数据
        if (DataUtil.valid(data.getColdStorageId())) {
            // 查询业务信息
            ColdStorageViewItem loadItem = coldStorageDao.getColdStorageViewById(data.getColdStorageId());
            if (DataUtil.noNullOrEmpty(loadItem)) {
                // 验证业务编码
                if (!businessCode.equals(loadItem.getBusinessCode())) {
                    return failure(MessageConst.BUSINESS_CODE_ERROR);
                }
                ColdStorageData loadData = loadColdStorageData(loadItem);

                allLoadData.setColdStorage(loadData);
            }
        }

        // 加载显示逝者部分信息
        // 死亡原因
        FuneralDeadItem funeralDeadItem = funeralDeadDao.getFuneralDeadByBusinessCode(businessCode);
        allLoadData.setFuneralDead(BeanUtil.copy2Bean(funeralDeadItem, new ColdStorageAllDeadData()));
        // 设置字典文本
        dictionaryWrapper.resetDataText(allLoadData.getFuneralDead());

        // 加载字典数据
        allLoadData.setDicts(dictionaryService.loadDictionaryMap(data.getDictTypeCodes()));

        // 加载服务规则
        String dictCode = EDictCode.EQUIPMENT_TYPE.getCode();
        allLoadData.setRuleItems(serviceItemDao.listServiceDictionaryRuleByDictCode(dictCode, ""));

        // 记载物品服务
        if (DataUtil.valid(data.getServiceItemTypeCode())) {
            String businessType = EBusinessType.USE_IN_COLD_STORAGE.getType();
            ArrayList<ServiceItem> serviceItems = serviceItemDao.listServiceItemByBusinessType(businessType);
            HashMap<String, ArrayList<ServiceItem>> dataMap = new HashMap<>(16);
            dataMap.put(businessType, serviceItems);
            allLoadData.setServiceItems(dataMap);
        }

        // 返回响应结果
        return successData(allLoadData);
    }
}
